package br.ucb.rest.persistencia.dao;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

public final class GenericDAO {
	
	private static GenericDAO instance;
	private EntityManager em;
	
	private GenericDAO(EntityManager util) {
		super();
		this.em = util;
	}
	
	public static GenericDAO getInstance(EntityManager em) {
		if (instance == null) {
			instance = new GenericDAO(em);
		}
		return instance;
	}
	public static void liberarInstancia() {
		instance = null;
	}
	
	public void doInsert(Serializable vo) throws HibernateException {
		try {
			em.persist(vo);
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public void doUpdate(Serializable vo) throws HibernateException {
		try {
			em.merge(vo);
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public void doDelete(Serializable vo) throws HibernateException {
		try {
			em.remove(vo);
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public Object doFindByKey(Class<? extends Serializable> tipo, Serializable key) throws HibernateException {
		try {
			return ((Session)em.getDelegate()).createCriteria(tipo).add(Restrictions.idEq(key)).setCacheable(true).uniqueResult();
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public List<? extends Serializable> recuperarTodos(Class<? extends Serializable> tipo, String ordenacao) throws HibernateException {
		try {
			Criteria criteria = ((Session)em.getDelegate()).createCriteria(tipo);
			if (ordenacao != null && ordenacao.length() > 0) {
				criteria.addOrder(Order.asc(ordenacao));
			}
			return criteria.list();
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public Object namedQueryResultadoUnico(String nome, Map<String, Object> parametros) throws HibernateException {
		try {
			Query query = em.createNamedQuery(nome);
			if (parametros != null && parametros.size() > 0) {
				for (String chave : parametros.keySet()) {
					query.setParameter(chave, parametros.get(chave));
				}
			}
			return query.getSingleResult();
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public List<? extends Serializable> namedQueryListaResultados(String nome, Map<String, Object> parametros) throws HibernateException {
		try {
			Query query = em.createNamedQuery(nome);
			if (parametros != null && parametros.size() > 0) {
				for (String chave : parametros.keySet()) {
					query.setParameter(chave, parametros.get(chave));
				}
			}
			return query.getResultList();
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public Object criteriaResultadoUnico(DetachedCriteria criteria) throws HibernateException {
		Session session = (Session) em.getDelegate();
		try {
			return criteria.getExecutableCriteria(session).uniqueResult();
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	public List<? extends Serializable> criteriaListaResultados(DetachedCriteria criteria) throws HibernateException {
		Session session = (Session) em.getDelegate();
		try {
			return criteria.getExecutableCriteria(session).list();
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	
	public void salvarVarios(Collection<? extends Serializable> lista) throws HibernateException {
		try {
			for (Serializable vo: lista) {
				em.persist(vo);
			}
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}
	
	public void deletarVarios(Collection<? extends Serializable> lista) throws HibernateException {
		try {
			for (Serializable vo: lista) {
				em.remove(vo);
			}
		}catch (Exception e) {
			throw new HibernateException(e);
		}
	}


}
